#include "uSPI.h"


void InitOutputPin(uint32 gpio_periph, uint32 pin, uint32 speed, bool set) 
{
    gpio_mode_set(gpio_periph, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, pin);
    gpio_output_options_set(gpio_periph, GPIO_OTYPE_PP, speed, pin);
    if (set)
        gpio_bit_set(gpio_periph, pin);
    else
        gpio_bit_reset(gpio_periph, pin);
}


void InitSPI_RC522() 
{
    rcu_periph_clock_enable(RCU_SPI1);

    gpio_af_set(SPI1_IO, GPIO_AF_0, SPI1_PINS);
    gpio_mode_set(SPI1_IO, GPIO_MODE_AF, GPIO_PUPD_NONE, SPI1_PINS);
    gpio_output_options_set(SPI1_IO, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, SPI1_PINS);

    InitOutputPin(RC522_RESET_IO, RC522_RESET_PIN, GPIO_OSPEED_50MHZ, true);
    InitOutputPin(RC522_CS_IO, RC522_CS_PIN, GPIO_OSPEED_50MHZ, true);

    spi_parameter_struct oParams;
    oParams.trans_mode = SPI_TRANSMODE_FULLDUPLEX;
    oParams.device_mode = SPI_MASTER;
    oParams.frame_size = SPI_FRAMESIZE_8BIT;
    oParams.clock_polarity_phase = SPI_CK_PL_HIGH_PH_2EDGE;
    oParams.nss = SPI_NSS_SOFT;
    oParams.prescale = SPI_PSC_8;               // RC522 SPI 10MBit/s
    oParams.endian = SPI_ENDIAN_MSB;
    if (SUCCESS != spi_init(SPI1, &oParams)) {
        return;
    }
    spi_enable(SPI1);
}

void InitSPI() {
//    InitSPI_LCD();
//    DelayMS(50);
    InitSPI_RC522();
}

#define SPI_TIMEOUT 2000

// SPI_FLAG_TBE: SPI ????????
// SPI_FLAG_RBNE: SPI ?????????

error SPI_WriteByte(uint32 ASPI, byte AByte, uint32 ATimeout) {
    // ???????????
    uint32 oTickEnd = GetSysTickMS() + ATimeout;
    while (RESET == spi_i2s_flag_get(ASPI, SPI_FLAG_TBE)) {
        if (SysTickAfter(oTickEnd)) {
            return 1;
        }
        __asm("NOP");
    }
    spi_i2s_data_transmit(ASPI, AByte);
    return 0;
}

error SPI_WriteBytes(uint32 ASPI, pbyte ABytes, uint16 ACount) {
    error oErr;
    while (ACount--) {
        oErr = SPI_WriteByte(ASPI, *ABytes, 100);
        if (oErr != 0) {
            return oErr;
        }
        ABytes++;
    }
    return 0;
}

error SPI_ReadByte(uint32 ASPI, pbyte AByte, uint32 ATimeout) {
    uint32_t oTickEnd = GetSysTickMS() + ATimeout;
    while (RESET == spi_i2s_flag_get(ASPI, SPI_FLAG_RBNE)) {
        if (SysTickAfter(oTickEnd)) {
            return ErrorInnerTimeout;
        }
        __asm("NOP");
    }
    *AByte = spi_i2s_data_receive(ASPI);
    return 0;
}

error SPI_SendByte(uint32 ASPI, byte ASendByte, pbyte AResByte) {
    error oErr;

    if (ASPI != SPI0) {
        SPI_CTL1(ASPI) |= SPI_CTL1_BYTEN; // ?? FIFO
    }

    oErr = SPI_WriteByte(ASPI, ASendByte, 1000);
    if (oErr != 0) {
        return oErr;
    }
    DelayUS(1);

    oErr = SPI_ReadByte(ASPI, AResByte, 1000);
    if (oErr != 0) {
        return oErr;
    }

    return 0;
}

error SPI_ReadByteDummy(uint32 ASPI, pbyte AResByte) {
    return SPI_SendByte(ASPI, 0xFF, AResByte);
}

//error SPI_ReadNBytes(uint32_t ASPI, uint8_t *AByte, uint16_t ACount) {
//    error oErr;
//    while (ACount--) {
//        oErr = SPI_ReadByte(ASPI, AByte, 100);
//        if (oErr != 0) {
//            return oErr;
//        }
//        AByte++;
//    }
//    return 0;
//}
